
#include "TFT_GC9D01N.h"
#include "Fonts.h"

//void  TFT_GC9D01N_Class::begin_tft_write()
//{
//    spi->take(&cfg);
//    cs->reset();
//    //  SET_BUS_WRITE_MODE;
//}

//void TFT_GC9D01N_Class::end_tft_write()
//{
//    // SPI_BUSY_CHECK;       // Check send complete and clean out unused rx data
//    cs->set();
//    spi->release();
//}

//void TFT_GC9D01N_Class::write_data8(uint8_t d)
//{
//    begin_tft_write();

//    dc->set();        // Play safe, but should already be in data mode  高电平1为数据

//    spi->transfer(d);

//    cs->reset();        // Allow more hold time for low VDI rail

//    end_tft_write();
//}

//void TFT_GC9D01N_Class::write_reg(uint8_t c)
//{
//    begin_tft_write();

//    dc->reset();       //高电平1为数据

//    spi->transfer(c);

//    dc->set();

//    end_tft_write();

//}

void TFT_GC9D01N_Class::write_reg(uint8_t val)
{
    //SPI 写命令时序开始
    spi->take(&cfg);
    dc->reset();
    cs->reset();
    spi->write(val);
    cs->set();
    dc->set();
    spi->release();
}
void TFT_GC9D01N_Class::write_data8(uint8_t val)
{
    spi->take(&cfg);
    dc->set();
    cs->reset();
    spi->write(val);
    cs->set();
    spi->release();
}
void TFT_GC9D01N_Class::write_data16(uint16_t val)
{
    spi->take(&cfg);
    dc->set();
    cs->reset();
    spi->write(val>>8);
    spi->write(val);
    cs->set();
    spi->release();
}
void TFT_GC9D01N_Class::write_data(uint8_t *ptr,uint32_t size)
{
    spi->take(&cfg);
    dc->set();
    cs->reset();
    spi->write_buf(ptr,size);
    cs->set();
    spi->release();
}

//init lcd
int TFT_GC9D01N_Class::begin()
{
    led->mode(OUTPUT_PP_PN);

    cfg.dev_num = cs->id;
    cfg.mode = Spi::MODE0;
    cfg.bit_order = Spi::MSB;
    if(spi->type == 1)
        cfg.prescaler = Spi::DIV2;
    else
        cfg.prescaler = Spi::DIV16;
    

    led->mode(OUTPUT_PP_PN);
    led->set();
    spi->begin(&cfg); 
    cs->mode(OUTPUT_PP_PN);
    cs->set();
    rst->mode(OUTPUT_PP_PN);
    rst->set();   
    dc->mode(OUTPUT_PP_PN);
    dc->set();
    
    

    // digitalWrite(TFT_BL, HIGH); //开启背光
    delay_ms(100);

    lcd_init();

    return 1;

}

void TFT_GC9D01N_Class::backlight(uint8_t state)
{
    led->write(state);// digitalWrite(TFT_BL, state);
}

/**
 * @brief   Select the block area to write to 选择写的块区域
 * @note
 * @param  Xstart:
 * @param  Xend:
 * @param  Ystart:
 * @param  Yend:
 * @retval None
 */
void TFT_GC9D01N_Class::BlockWrite(unsigned int Xstart, unsigned int Xend, unsigned int Ystart, unsigned int Yend)
{

    write_reg(0x2A);
//    write_data8(Xstart >> 8);
//    write_data8(Xstart);
//    write_data8(Xend >> 8);
//    write_data8(Xend);
    write_data16(Xstart);
    write_data16(Xend);

    write_reg(0x2B);
//    write_data8(Ystart >> 8);
//    write_data8(Ystart);
//    write_data8(Yend >> 8);
//    write_data8(Yend);
    write_data16(Ystart);
    write_data16(Yend);

    write_reg(0x2c);
    write_reg(0x2c);

}

/**
 * @brief Drawing function
 * @note
 * @param  Xstart:  starting x-coordinate x坐标开始
 * @param  Ystart:  starting y-coordinate y坐标结束
 * @param  w:       The width of the image
 * @param  h:       The height of the image
 * @param  color:
 * @retval None
 */
void TFT_GC9D01N_Class::DrawImage(unsigned int Xstart, unsigned int Ystart, unsigned int w, unsigned int h, uint16_t *color)
{
    unsigned int i, j;
    unsigned int Xend = Xstart + w;
    unsigned int Yend = Ystart + h;

    BlockWrite(Xstart, Xend - 1, Ystart, Yend - 1);
    uint32_t len = w * h;


#if LANDSCAPE

    spi->take(&cfg);
    cs->reset();
    dc->set();
    for (int i = 0; i <= h; i++) {
        for (int j = w - 1 ; j >= 0 ; j--) {
            spi->transfer16(*(color + ((j * (Yend - Ystart)) + (i))));
        }
    }
    cs->set();
    spi->release();

#else

    SPI.beginTransaction(SPISettings(SPI_FREQUENCY, MSBFIRST, SPI_MODE0));
    cs->reset();
    dc->set();
    for (int i = 0; i <= h; i++) {
        for (int j = w - 1 ; j >= 0 ; j--) {
            SPI.transfer16(*color);
            color++;
        }
    }
    cs->set();
    SPI.endTransaction();

#endif

}

void TFT_GC9D01N_Class::fill_rect(int16_t x0, int16_t y0,  int16_t x1, int16_t y1, uint32_t color)
{
    unsigned int i, j;
    uint8_t dx, dy;
    dx = x1 - x0 + 1;
    dy = y1 - y0 + 1;
    BlockWrite(x0, x1 -1, y0, y1 - 1);
    
    
    spi->take(&cfg);
    cs->reset();
    dc->set();
    for (i = 0; i <= dx*dy; i++) {
        spi->transfer16(color);
    }
    cs->set();
    spi->release();

}

void TFT_GC9D01N_Class::DispColor(unsigned int Xstart, unsigned int Ystart, unsigned int Xend, unsigned int Yend, unsigned int color)
{


    unsigned int i, j;
    uint32_t len = TFT_HEIGHT * TFT_WIDTH;
    BlockWrite(Xstart, Xend , Ystart, Yend );
    
    uint8_t dx, dy;
    dx = Xend - Xstart + 1;
    dy = Yend - Ystart + 1;
    
    spi->take(&cfg);
    cs->reset();
    dc->set();
    for (i = 0; i < dx*dy; i++) {
        spi->transfer16(color);
    }
    cs->set();
    spi->release();

}

void TFT_GC9D01N_Class::draw_pixel(int16_t x, int16_t y,uint32_t color)
{
    uint8_t dx, dy;

    BlockWrite(x, x +1, y, y + 1);
    
    
    spi->take(&cfg);
    cs->reset();
    dc->set();
    spi->transfer16(color);
    cs->set();
    spi->release();
}
void TFT_GC9D01N_Class::fill_screen(uint32_t color)
{
    

    unsigned int i, j;
    uint32_t len = TFT_HEIGHT * TFT_WIDTH;
    BlockWrite(0, TFT_WIDTH - 1, 0, TFT_HEIGHT - 1);

    spi->take(&cfg);
    cs->reset();
    dc->set();
    for (i = 0; i <= TFT_HEIGHT; i++) {
        for (j = 0; j < TFT_WIDTH; j++) {
            spi->transfer16(color);
        }
    }
    cs->set();
    spi->release();
}

void TFT_GC9D01N_Class::WriteOneDot(unsigned int color)
{


    cs->reset();
    dc->set();

    write_data8(color >> 8);
    write_data8(color);

    cs->set();

}

unsigned char ToOrd( char ch)
{
    if (ch < 32) {
        ch = 95;
    } else if ((ch >= 32) && (ch <= 47)) {
        ch = (ch - 32) + 10 + 62;
    } else if ((ch >= 48) && (ch <= 57)) {
        ch = ch - 48;
    } else if ((ch >= 58) && (ch <= 64)) {
        ch = (ch - 58) + 10 + 62 + 16;
    } else if ((ch >= 65) && (ch <= 126)) {
        ch = (ch - 65) + 10;
    } else if (ch > 126) {
        ch = 95;
    }

    return ch;
}

void hz816_s90(const unsigned char *p_ucHz, unsigned char *p_ucResult) //A conversion function that rotates an 8x16 character font 90 degrees clockwise 把8x16字符字模顺时针旋转90度的转换函数
{

    unsigned char a;

    unsigned char b;

    unsigned char c;

    unsigned char uiBuffer[16];
    for (a = 0; a < 16; a++)

    {
        uiBuffer[a] = p_ucHz[a];
    }

    c = 0;

    for (a = 0; a < 8; a++)

    {

        for (b = 0; b < 8; b++)

        {

            p_ucResult[c] = p_ucResult[c] << 1;

            p_ucResult[c] = p_ucResult[c] & 0xfe;

            if (uiBuffer[15 - b] >= 0x80)

            {

                p_ucResult[c] = p_ucResult[c] + 1;

            }

            uiBuffer[15 - b] = uiBuffer[15 - b] << 1;


        }

        c++;

        for (b = 0; b < 8; b++)

        {

            p_ucResult[c] = p_ucResult[c] << 1;

            p_ucResult[c] = p_ucResult[c] & 0xfe;

            if (uiBuffer[7 - b] >= 0x80)

            {

                p_ucResult[c] = p_ucResult[c] + 1;

            }

            uiBuffer[7 - b] = uiBuffer[7 - b] << 1;

        }

        c++;

    }

}

void hz816_s270(const unsigned char *p_ucHz, unsigned char *p_ucResult)
{

    unsigned char a;

    unsigned char b;

    unsigned char c;

    unsigned char uiBuffer[16];


    for (a = 0; a < 16; a++)

    {

        uiBuffer[a] = p_ucHz[a];

    }

    c = 0;

    for (a = 0; a < 8; a++)

    {

        for (b = 0; b < 8; b++)

        {

            p_ucResult[c] = p_ucResult[c] << 1;


            if ((uiBuffer[b] & 0x01)  >= 0x01)

            {

                p_ucResult[c] = p_ucResult[c] + 1;

            }

            uiBuffer[b] = uiBuffer[b] >> 1;


        }

        c++;

        for (b = 0; b < 8; b++)

        {

            p_ucResult[c] = p_ucResult[c] << 1;

            if ((uiBuffer[8 + b] & 0x01) >= 0x01)

            {

                p_ucResult[c] = p_ucResult[c] + 1;

            }

            uiBuffer[8 + b] = uiBuffer[8 + b] >> 1;

        }

        c++;

    }

}

void  TFT_GC9D01N_Class::DispOneChar( char ord, unsigned int Xstart, unsigned int Ystart, unsigned int TextColor, unsigned int BackColor) // ord:0~95
{
    unsigned char  hou[16] = {0};
    unsigned char i, j;
    unsigned char  *p;
    unsigned char dat;
    unsigned int index;


    index = ord;

    if (index > 95)
        index = 95;

    index = index * ((FONT_W / 8) * FONT_H);

    p = ascii;
    p = p + index ;


#if LANDSCAPE

    int y = Ystart;
    y = y - 23;
    Ystart = abs(y);


    BlockWrite(Ystart, Ystart + (FONT_H - 1), Xstart, Xstart + (FONT_W - 1));

    hz816_s90(p, hou);

    for (i = 0; i < (FONT_W / 8 * FONT_H); i++) {
        dat = hou[i];
        for (j = 0; j < 8; j++) {
            if ((dat << j) & 0x80) {
                WriteOneDot(TextColor);
            } else {
                WriteOneDot(BackColor);
            }
        }
    }
#else
    BlockWrite(Xstart, Xstart + (FONT_W - 1), Ystart, Ystart + (FONT_H - 1));


    for (i = 0; i < (FONT_W / 8 * FONT_H); i++) {
        dat = *p++;
        for (j = 0; j < 8; j++) {
            if ((dat << j) & 0x80) {
                WriteOneDot(TextColor);
            } else {
                WriteOneDot(BackColor);
            }
        }
    }

#endif
}

void TFT_GC9D01N_Class::DispStr( char *str, unsigned int Xstart, unsigned int Ystart, unsigned int TextColor, unsigned int BackColor)
{

    while (!(*str == '\0')) {
        DispOneChar(ToOrd(*str++), Xstart, Ystart, TextColor, BackColor);

#if LANDSCAPE
        if (Xstart > ((TFT_HEIGHT - 1) - FONT_W)) {
            //Xstart = 0;
            //Ystart = Ystart - FONT_H;
        } else {
            Xstart = Xstart + FONT_W;
        }

        if (Ystart > ((TFT_WIDTH - 1) - FONT_H)) {
            Ystart = 23;
        }
#else


        if (Xstart > ((TFT_WIDTH - 1) - FONT_W)) {
            Xstart = 0;
            Ystart = Ystart + FONT_H;
        } else {
            Xstart = Xstart + FONT_W;
        }

        if (Ystart > ((TFT_HEIGHT - 1) - FONT_H)) {
            Ystart = 0;
        }

#endif


    }
    BlockWrite(0, TFT_WIDTH - 1, 0, TFT_HEIGHT - 1);
}





void TFT_GC9D01N_Class::lcd_init()
{

    rst->set();
    delay_ms(80);

    rst->reset();
    delay_ms(80);

    rst->set();
    delay_ms(480);


    write_reg(0xFE);
    write_reg(0xEF);

    write_reg(0x80);
    write_data8(0xFF);

    write_reg(0x81);
    write_data8(0xFF);

    write_reg(0x82);
    write_data8(0xFF);

    write_reg(0x83);
    write_data8(0xFF);

    write_reg(0x84);
    write_data8(0xFF);

    write_reg(0x85);
    write_data8(0xFF);

    write_reg(0x86);
    write_data8(0xFF);

    write_reg(0x87);
    write_data8(0xFF);

    write_reg(0x88);
    write_data8(0xFF);

    write_reg(0x89);
    write_data8(0xFF);

    write_reg(0x8A);
    write_data8(0xFF);

    write_reg(0x8B);
    write_data8(0xFF);

    write_reg(0x8C);
    write_data8(0xFF);

    write_reg(0x8D);
    write_data8(0xFF);

    write_reg(0x8E);
    write_data8(0xFF);

    write_reg(0x8F);
    write_data8(0xFF);

    write_reg(0x3A);
    write_data8(0x05);

    write_reg(0xEC);
    write_data8(0x11);


    write_reg(0x7E);
    write_data8(0x7a);


    write_reg(0x74);
    write_data8(0x02);
    write_data8(0x0E);
    write_data8(0x00);
    write_data8(0x00);
    write_data8(0x28);
    write_data8(0x00);
    write_data8(0x00);

    write_reg(0x98);
    write_data8(0x3E);
    write_reg(0x99);
    write_data8(0x3E);




    write_reg(0xB5);
    write_data8(0x0E);
    write_data8(0x0E);
    write_reg(0x60);
    write_data8(0x38);
    write_data8(0x09);
    write_data8(0x6D);
    write_data8(0x67);


    write_reg(0x63);
    write_data8(0x38);
    write_data8(0xAD);
    write_data8(0x6D);
    write_data8(0x67);
    write_data8(0x05);


    write_reg(0x64);
    write_data8(0x38);
    write_data8(0x0B);
    write_data8(0x70);
    write_data8(0xAB);
    write_data8(0x6D);
    write_data8(0x67);


    write_reg(0x66);
    write_data8(0x38);
    write_data8(0x0F);
    write_data8(0x70);
    write_data8(0xAF);
    write_data8(0x6d);
    write_data8(0x67);

    write_reg(0x6A);
    write_data8(0x00);
    write_data8(0x00);

    write_reg(0x68);
    write_data8(0x3B);
    write_data8(0x08);
    write_data8(0x04);
    write_data8(0x00);
    write_data8(0x04);
    write_data8(0x64);
    write_data8(0x67);



    write_reg(0x6C);
    write_data8(0x22);
    write_data8(0x02);
    write_data8(0x22);
    write_data8(0x02);
    write_data8(0x22);
    write_data8(0x22);
    write_data8(0x50);

    write_reg(0x6E);
    write_data8(0x00);
    write_data8(0x00);
    write_data8(0x00);
    write_data8(0x00);
    write_data8(0x07);
    write_data8(0x01);
    write_data8(0x13);
    write_data8(0x11);

    write_data8(0x0B);
    write_data8(0x09);
    write_data8(0x16);
    write_data8(0x15);
    write_data8(0x1D);
    write_data8(0x1E);
    write_data8(0x00);
    write_data8(0x00);

    write_data8(0x00);
    write_data8(0x00);
    write_data8(0x1E);

    write_data8(0x1D);
    write_data8(0x15);
    write_data8(0x16);
    write_data8(0x0A);
    write_data8(0x0C);

    write_data8(0x12);
    write_data8(0x14);
    write_data8(0x02);
    write_data8(0x08);
    write_data8(0x00);
    write_data8(0x00);
    write_data8(0x00);
    write_data8(0x00);


    write_reg(0xA9);
    write_data8(0x1B);

    write_reg(0xA8);
    write_data8(0x6B);

    write_reg(0xA8);
    write_data8(0x6D);

    write_reg(0xA7);
    write_data8(0x40);

    write_reg(0xAD);
    write_data8(0x47);


    write_reg(0xAF);
    write_data8(0x73);

    write_reg(0xAF);
    write_data8(0x73);

    write_reg(0xAC);
    write_data8(0x44);

    write_reg(0xA3);
    write_data8(0x6C);

    write_reg(0xCB);
    write_data8(0x00);

    write_reg(0xCD);
    write_data8(0x22);


    write_reg(0xC2);
    write_data8(0x10);

    write_reg(0xC5);
    write_data8(0x00);

    write_reg(0xC6);
    write_data8(0x0E);

    write_reg(0xC7);
    write_data8(0x1f);

    write_reg(0xC8);
    write_data8(0x0E);

    write_reg(0xbf);
    write_data8(0x00);

    write_reg(0xF9);
    write_data8(0x20);

    write_reg(0x9b);
    write_data8(0x3b);
    write_reg(0x93);
    write_data8(0x33);
    write_data8(0x7f);
    write_data8(0x00);

    write_reg(0x70);
    write_data8(0x0E);
    write_data8(0x0f);
    write_data8(0x03);
    write_data8(0x0e);
    write_data8(0x0f);
    write_data8(0x03);

    write_reg(0x71);
    write_data8(0x0e);
    write_data8(0x16);
    write_data8(0x03);

    write_reg(0x91);
    write_data8(0x0e);
    write_data8(0x09);



    write_reg(0xc3);
    write_data8(0x2c);
    write_reg(0xc4);
    write_data8(0x1a);




    write_reg(0xf0);
    write_data8(0x51);
    write_data8(0x13);
    write_data8(0x0c);
    write_data8(0x06);
    write_data8(0x00);
    write_data8(0x2f);

    write_reg(0xf2);
    write_data8(0x51);
    write_data8(0x13);
    write_data8(0x0c);
    write_data8(0x06);
    write_data8(0x00);
    write_data8(0x33);

    write_reg(0xf1);
    write_data8(0x3c);
    write_data8(0x94);
    write_data8(0x4f);
    write_data8(0x33);
    write_data8(0x34);
    write_data8(0xCf);

    write_reg(0xf3);
    write_data8(0x4d);
    write_data8(0x94);
    write_data8(0x4f);
    write_data8(0x33);
    write_data8(0x34);
    write_data8(0xCf);




#define TFT_MAD_MY  0x80
#define TFT_MAD_MX  0x40
#define TFT_MAD_MV  0x20
#define TFT_MAD_ML  0x10

    write_reg(0x36);

//#if LANDSCAPE
//write_data8(0x00 |  TFT_MAD_MX | TFT_MAD_MY);

#if (LANDSCAPE==2)||(PORTRAIT==2)
    write_data8(0x00);
#else
    write_data8(0x00 |  TFT_MAD_MX | TFT_MAD_MY);
#endif
    write_reg(0x11);
    delay_ms(200);
    write_reg(0x29);
    write_reg(0x2C);


}

